import languages.*;

import java.util.ArrayList;

public class Similarity {
	
	public Similarity(){
	
	}

    public Case mostSimilar(Case inputCase, ArrayList<Case> cases) {
        double maxTeamSize = inputCase.teamSize;
        double minTeamSize = inputCase.teamSize;
        double maxDatabaseSize = inputCase.databaseSize;
        double minDatabaseSize = inputCase.databaseSize;
        double maxExpectedUsers = inputCase.expectedUsers;
        double minExpectedUsers = inputCase.expectedUsers;
        double maxTestsRequired = inputCase.testsRequired;
        double minTestsRequired = inputCase.testsRequired;
        double maxLinesOfCode = inputCase.linesOfCode;
        double minLinesOfCode = inputCase.linesOfCode;
        double maxEffortDays = inputCase.effortDays;
        double minEffortDays = inputCase.effortDays;
        double maxTeamExperience = inputCase.teamExperience;
        double minTeamExperience = inputCase.teamExperience;

        for (Case c : cases) {
            if (c.teamSize > maxTeamSize) maxTeamSize = c.teamSize;
            if (c.teamSize < minTeamSize) minTeamSize = c.teamSize;

            if (c.databaseSize > maxDatabaseSize) maxDatabaseSize = c.databaseSize;
            if (c.databaseSize < minDatabaseSize) minDatabaseSize = c.databaseSize;

            if (c.expectedUsers > maxExpectedUsers) maxExpectedUsers = c.expectedUsers;
            if (c.expectedUsers < minExpectedUsers) minExpectedUsers = c.expectedUsers;

            if (c.testsRequired > maxTestsRequired) maxTestsRequired = c.testsRequired;
            if (c.testsRequired < minTestsRequired) minTestsRequired = c.testsRequired;

            if (c.linesOfCode > maxLinesOfCode) maxLinesOfCode = c.linesOfCode;
            if (c.linesOfCode < minLinesOfCode) minLinesOfCode = c.linesOfCode;

            if (c.effortDays > maxEffortDays) maxEffortDays = c.effortDays;
            if (c.effortDays < minEffortDays) minEffortDays = c.effortDays;

            if (c.teamExperience > maxTeamExperience) maxTeamExperience = c.teamExperience;
            if (c.teamExperience < minTeamExperience) minTeamExperience = c.teamExperience;
        }

        Case mostSimilarCase = null;
        double similarityPoints = Double.MIN_VALUE;

        for (Case c : cases) {
            double points = 0f;


            if ((maxTeamSize - minTeamSize) > 0d) {
                points += Math.pow(Math.abs(inputCase.teamSize - c.teamSize) / (maxTeamSize - minTeamSize), 2);
            }

            points += (inputCase.webBased == c.webBased) ? 0f : 0.5f;
            points += (inputCase.crossPlatform == c.crossPlatform) ? 0f : 0.5f;

            if ((maxDatabaseSize - minDatabaseSize) > Float.MIN_VALUE)
                points += Math.abs(inputCase.databaseSize - c.databaseSize) / (maxDatabaseSize - minDatabaseSize);

            if ((maxExpectedUsers - minExpectedUsers) > Float.MIN_VALUE)
                points += Math.abs(inputCase.expectedUsers - c.expectedUsers) / (maxExpectedUsers - minExpectedUsers);

            if ((maxTestsRequired - minTestsRequired) > Float.MIN_VALUE)
                points += Math.abs(inputCase.testsRequired - c.testsRequired) / (maxTestsRequired - minTestsRequired);

            if ((maxLinesOfCode - minLinesOfCode) > Float.MIN_VALUE)
                points += Math.abs(inputCase.linesOfCode - c.linesOfCode) / (maxLinesOfCode - minLinesOfCode);

            if ((maxEffortDays - minEffortDays) > Float.MIN_VALUE)
                points += Math.abs(inputCase.effortDays - c.effortDays) / (maxEffortDays - minEffortDays);

            if ((maxTeamExperience - minTeamExperience) > Float.MIN_VALUE)
                points += Math.abs(inputCase.teamExperience - c.teamExperience) / (maxTeamExperience - minTeamExperience);

            points += 1 - inputCase.language.similarity(c.language);

            double totalPoints = 1 - Math.sqrt(points / 10);

            if (totalPoints >= similarityPoints || mostSimilarCase == null) {
                similarityPoints = totalPoints;
                mostSimilarCase = c;
            }
        }

        return mostSimilarCase;
    }
}
